package com.maoatao.easycodegen.core;

import com.baomidou.mybatisplus.annotation.IdType;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.create.table.ColumnDefinition;
import net.sf.jsqlparser.statement.create.table.CreateTable;
import net.sf.jsqlparser.statement.create.table.Index;

import java.util.ArrayList;
import java.util.List;

/**
 * DDL解析器 (仅mysql测试)
 *
 * @author MaoAtao
 * @date 2025-10-04
 */
public class DdlParser {

    /**
     * 解析DDL语句
     *
     * @param ddl    DDL语句
     * @param config 配置信息
     * @return 表信息
     */
    public TableInfo parse(String ddl, GeneratorConfig config) {
        // 检查DDL是否为空
        if (ddl == null || ddl.trim().isEmpty()) {
            throw new IllegalArgumentException("DDL语句不能为空");
        }

        try {
            // 使用JSqlParser解析DDL
            Statement statement = CCJSqlParserUtil.parse(ddl);
            if (!(statement instanceof CreateTable createTable)) {
                throw new IllegalArgumentException("DDL语句必须是CREATE TABLE语句");
            }

            TableInfo tableInfo = new TableInfo();

            String tableName = removeBackticks(createTable.getTable().getName());

            if (tableName != null && tableName.trim().length() > 0) {
                // 解析表名
                tableInfo.setTableName(tableName);
            } else {
                throw new IllegalArgumentException("DDL语句的表名不能为空");
            }


            // 解析表备注
            String tableComment = parseTableComment(createTable);
            if (tableComment != null && tableComment.trim().length() > 0) {
                // 如果备注的最后一个字是"表"，则去掉这个字
                if (tableComment.endsWith("表")) {
                    tableComment = tableComment.substring(0, tableComment.length() - 1);
                }
                tableInfo.setComment(tableComment);
            } else {
                tableInfo.setComment(tableInfo.getTableName());
            }

            // 解析列信息
            parseColumns(createTable, tableInfo, config);

            // 检查必要字段
            validateRequiredFields(tableInfo);

            // 计算类名和实例名
            calculateClassAndInstanceName(tableInfo, config);

            return tableInfo;
        } catch (JSQLParserException e) {
            throw new IllegalArgumentException("DDL解析失败: " + e.getMessage(), e);
        }
    }

    /**
     * 解析表备注
     *
     * @param createTable CreateTable语句
     * @return 表备注
     */
    private String parseTableComment(CreateTable createTable) {
        // 尝试从表选项中获取注释
        if (createTable.getTableOptionsStrings() != null) {
            List<String> options = createTable.getTableOptionsStrings();
            for (int i = 0; i < options.size() - 1; i++) {
                if ("COMMENT".equalsIgnoreCase(options.get(i))) {
                    // 根据调试结果，注释内容在 i+2 位置
                    // 检查数组是否越界
                    if (i + 2 < options.size()) {
                        String comment = options.get(i + 2);
                        // 移除引号
                        if ((comment.startsWith("'") && comment.endsWith("'")) ||
                                (comment.startsWith("\"") && comment.endsWith("\""))) {
                            comment = comment.substring(1, comment.length() - 1);
                        }
                        return comment;
                    }
                }
            }
        }
        return null;
    }

    /**
     * 解析列信息
     */
    private void parseColumns(CreateTable createTable, TableInfo tableInfo, GeneratorConfig config) {
        List<ColumnInfo> columns = new ArrayList<>();

        // 解析列定义
        for (ColumnDefinition columnDef : createTable.getColumnDefinitions()) {
            ColumnInfo columnInfo = new ColumnInfo();

            // 列名
            String columnName = removeBackticks(columnDef.getColumnName());
            columnInfo.setColumnName(columnName);

            // 数据库类型
            String dbType = columnDef.getColDataType().getDataType();
            // 处理带长度的类型，如varchar(100) -> varchar
            if (dbType.contains("(")) {
                dbType = dbType.substring(0, dbType.indexOf("(")).trim();
            }
            columnInfo.setDbType(dbType.toLowerCase());

            // 检查是否为主键
            if (createTable.getIndexes() != null) {
                for (Index index : createTable.getIndexes()) {
                    if (index.getType().equalsIgnoreCase("PRIMARY KEY") &&
                            index.getColumnsNames().contains(columnName)) {
                        columnInfo.setPrimaryKey(true);
                        break;
                    }
                }
            }

            // 获取Java类型
            String javaType = config.getFieldTypeMapping().get(columnInfo.getDbType());
            if (javaType == null) {
                throw new IllegalArgumentException("未知的数据库类型: " + columnInfo.getDbType());
            }
            columnInfo.setJavaType(javaType);

            // 检查列约束中的主键
            if (columnDef.getColumnSpecs() != null) {
                for (String spec : columnDef.getColumnSpecs()) {
                    if (spec.equalsIgnoreCase("PRIMARY") || spec.equalsIgnoreCase("KEY")) {
                        columnInfo.setPrimaryKey(true);
                        break;
                    }
                }
            }

            if (columnInfo.isPrimaryKey()) {
                // 检查是否有AUTO_INCREMENT属性（最高优先级）
                boolean hasAutoIncrement = false;
                if (columnDef.getColumnSpecs() != null) {
                    for (String spec : columnDef.getColumnSpecs()) {
                        if (spec.equalsIgnoreCase("AUTO_INCREMENT")) {
                            columnInfo.setIdType("IdType.AUTO");
                            hasAutoIncrement = true;
                            break;
                        }
                    }
                }

                if (hasAutoIncrement) {
                    // 数据库主键自增，且字段映射为Integer，则将字段映射为Long
                    if (Integer.class.getSimpleName().equalsIgnoreCase(javaType)) {
                        columnInfo.setJavaType(Long.class.getSimpleName());
                    }
                }
                // 如果是主键但没有AUTO_INCREMENT，则根据配置设置主键类型
                else {
                    // 如果配置中设置了主键类型，则使用配置的值
                    if (config.getIdType() != null) {
                        columnInfo.setIdType(buildIdType(config.getIdType()));
                    } else {
                        // 默认使用ASSIGN_ID(雪花算法)
                        columnInfo.setIdType(buildIdType(IdType.ASSIGN_ID));
                    }
                }
            }

            // 获取备注
            if (columnDef.getColumnSpecs() != null) {
                for (int i = 0; i < columnDef.getColumnSpecs().size() - 1; i++) {
                    if ("COMMENT".equalsIgnoreCase(columnDef.getColumnSpecs().get(i))) {
                        String comment = columnDef.getColumnSpecs().get(i + 1);
                        // 移除引号
                        if ((comment.startsWith("'") && comment.endsWith("'")) ||
                                (comment.startsWith("\"") && comment.endsWith("\""))) {
                            comment = comment.substring(1, comment.length() - 1);
                        }
                        columnInfo.setComment(comment);
                        break;
                    }
                }
            }

            // 转换为Java字段名（下划线转驼峰）
            columnInfo.setJavaFieldName(toCamelCase(columnName));

            // 设置字段注释，如果comment为空，则使用columnName
            if (columnInfo.getComment() != null && !columnInfo.getComment().isEmpty()) {
                columnInfo.setFieldComment(columnInfo.getComment());
            } else {
                columnInfo.setFieldComment(columnInfo.getColumnName());
            }

            columns.add(columnInfo);
        }

        tableInfo.setColumns(columns);
    }

    private String buildIdType(IdType idType) {
        return switch (idType) {
            case AUTO -> "IdType.AUTO";
            case NONE -> "IdType.NONE";
            case INPUT -> "IdType.INPUT";
            case ASSIGN_ID -> "IdType.ASSIGN_ID";
            case ASSIGN_UUID -> "IdType.ASSIGN_UUID";
        };
    }

    /**
     * 检查必要字段
     */
    private void validateRequiredFields(TableInfo tableInfo) {
        // 检查是否有主键且为id
        ColumnInfo primaryKey = tableInfo.getPrimaryKey();
        if (primaryKey == null) {
            throw new IllegalArgumentException("表必须有主键");
        }
        if (!"id".equals(primaryKey.getColumnName())) {
            throw new IllegalArgumentException("主键列名必须为id");
        }

        // 检查是否有创建时间和修改时间字段
        boolean hasGmtCreate = false;
        boolean hasGmtModified = false;

        for (ColumnInfo column : tableInfo.getColumns()) {
            if ("gmt_create".equals(column.getColumnName())) {
                hasGmtCreate = true;
            }
            if ("gmt_modified".equals(column.getColumnName())) {
                hasGmtModified = true;
            }
        }

        if (!hasGmtCreate) {
            throw new IllegalArgumentException("表必须包含gmt_create字段");
        }
        if (!hasGmtModified) {
            throw new IllegalArgumentException("表必须包含gmt_modified字段");
        }
    }

    /**
     * 计算类名和实例名
     */
    private void calculateClassAndInstanceName(TableInfo tableInfo, GeneratorConfig config) {
        String tableName = tableInfo.getTableName();
        String tablePrefix = config.getTablePrefix();

        String baseName;
        if (tablePrefix != null && !tablePrefix.isEmpty() && tableName.startsWith(tablePrefix)) {
            baseName = tableName.substring(tablePrefix.length());
        } else {
            baseName = tableName;
        }

        // 大驼峰命名（类名）
        tableInfo.setClassName(toCamelCase(baseName, true));

        // 小驼峰命名（实例名）
        tableInfo.setInstanceName(toCamelCase(baseName, false));
    }

    /**
     * 下划线转驼峰
     *
     * @param str                   下划线字符串
     * @param capitalizeFirstLetter 是否首字母大写
     * @return 驼峰字符串
     */
    private String toCamelCase(String str, boolean capitalizeFirstLetter) {
        if (str == null || str.isEmpty()) {
            return str;
        }

        StringBuilder result = new StringBuilder();
        boolean capitalizeNext = capitalizeFirstLetter;

        for (char c : str.toCharArray()) {
            if (c == '_') {
                capitalizeNext = true;
            } else if (capitalizeNext) {
                result.append(Character.toUpperCase(c));
                capitalizeNext = false;
            } else {
                result.append(Character.toLowerCase(c));
            }
        }

        return result.toString();
    }

    /**
     * 下划线转小驼峰
     */
    private String toCamelCase(String str) {
        return toCamelCase(str, false);
    }

    /**
     * 移除字段名的反引号
     *
     * @param columnName 字段名
     * @return 移除反引号后的字段名
     */
    private String removeBackticks(String columnName) {
        if (columnName != null && columnName.length() >= 2 &&
                columnName.startsWith("`") && columnName.endsWith("`")) {
            return columnName.substring(1, columnName.length() - 1);
        }
        return columnName;
    }
}
